
-- declare local variables
--// exportstring( string )
--// returns a "Lua" portable version of the string

if minetest.setting_getbool("lunonodes_alertowner")~=true then minetest.setting_set("lunonodes_alertowner","false") end

function exportstring( s )
  s = string.format( "%q",s )
  -- to replace
  s = string.gsub( s,"\\\n","\\n" )
  s = string.gsub( s,"\r","\\r" )
  s = string.gsub( s,string.char(26),"\"..string.char(26)..\"" )
  return s
end
--// The Save Function
function table_save(  tbl,filename )
   local charS,charE = "   ","\n"
   local file,err
   -- create a pseudo file that writes to a string and return the string
   if not filename then
      file =  { write = function( self,newstr ) self.str = self.str..newstr end, str = "" }
      charS,charE = "",""
   -- write table to tmpfile
   elseif filename == true or filename == 1 then
      charS,charE,file = "","",io.tmpfile()
   -- write table to file
   -- use io.open here rather than io.output, since in windows when clicking on a file opened with io.output will create an error
   else
      file,err = io.open( filename, "w" )
      if err then return _,err end
   end
   -- initiate variables for save procedure
   local tables,lookup = { tbl },{ [tbl] = 1 }
   file:write( "return {"..charE )
   for idx,t in ipairs( tables ) do
      if filename and filename ~= true and filename ~= 1 then
         file:write( "-- Table: {"..idx.."}"..charE )
      end
      file:write( "{"..charE )
      local thandled = {}
      for i,v in ipairs( t ) do
         thandled[i] = true
         -- escape functions and userdata
         if type( v ) ~= "userdata" then
            -- only handle value
            if type( v ) == "table" then
               if not lookup[v] then
                  table.insert( tables, v )
                  lookup[v] = #tables
               end
               file:write( charS.."{"..lookup[v].."},"..charE )
            elseif type( v ) == "function" then
               file:write( charS.."loadstring("..exportstring(string.dump( v )).."),"..charE )
            else
               local value =  ( type( v ) == "string" and exportstring( v ) ) or tostring( v )
               file:write(  charS..value..","..charE )
            end
         end
      end
      for i,v in pairs( t ) do
         -- escape functions and userdata
         if (not thandled[i]) and type( v ) ~= "userdata" then
            -- handle index
            if type( i ) == "table" then
               if not lookup[i] then
                  table.insert( tables,i )
                  lookup[i] = #tables
               end
               file:write( charS.."[{"..lookup[i].."}]=" )
            else
               local index = ( type( i ) == "string" and "["..exportstring( i ).."]" ) or string.format( "[%d]",i )
               file:write( charS..index.."=" )
            end
            -- handle value
            if type( v ) == "table" then
               if not lookup[v] then
                  table.insert( tables,v )
                  lookup[v] = #tables
               end
               file:write( "{"..lookup[v].."},"..charE )
            elseif type( v ) == "function" then
               file:write( "loadstring("..exportstring(string.dump( v )).."),"..charE )
            else
               local value =  ( type( v ) == "string" and exportstring( v ) ) or tostring( v )
               file:write( value..","..charE )
            end
         end
      end
      file:write( "},"..charE )
   end
   file:write( "}" )
   -- Return Values
   -- return stringtable from string
   if not filename then
      -- set marker for stringtable
      return file.str.."--|"
   -- return stringttable from file
   elseif filename == true or filename == 1 then
      file:seek ( "set" )
      -- no need to close file, it gets closed and removed automatically
      -- set marker for stringtable
      return file:read( "*a" ).."--|"
   -- close file and return 1
   else
      file:close()
      return 1
   end
end

--// The Load Function
function table_load( sfile )
   -- catch marker for stringtable
   if string.sub( sfile,-3,-1 ) == "--|" then
      tables,err = loadstring( sfile )
   else
      tables,err = loadfile( sfile )
   end
   if err then return _,err
   end
   tables = tables()
   for idx = 1,#tables do
      local tolinkv,tolinki = {},{}
      for i,v in pairs( tables[idx] ) do
         if type( v ) == "table" and tables[v[1]] then
            table.insert( tolinkv,{ i,tables[v[1]] } )
         end
         if type( i ) == "table" and tables[i[1]] then
            table.insert( tolinki,{ i,tables[i[1]] } )
         end
      end
      -- link values, first due to possible changes of indices
      for _,v in ipairs( tolinkv ) do
         tables[idx][v[1]] = v[2]
      end
      -- link indices
      for _,v in ipairs( tolinki ) do
         tables[idx][v[2]],tables[idx][v[1]] =  tables[idx][v[1]],nil
      end
   end
   return tables[1]
end

--local owners_db_filename = minetest.get_worldpath().. "/owners.tbl"
--local owners_db_filename = minetest.get_worldpath("node_ownership") .. "/owners.tbl"
owners_db_filename = minetest.get_worldpath().. "/lunonodes.tbl" --Antigamente: areas.tbl

owner_defs = table_load(owners_db_filename)

if type(owner_defs) ~= "table" then
	owner_defs = {}
end

function IsPlayerNodeOwner(pos, name)
	r = true
	for _,def in pairs(owner_defs) do
		if pos.x >= def.x1 and pos.x <= def.x2 or
			pos.x <= def.x1 and pos.x >= def.x2 then
			
			if pos.y >= def.y1 and pos.y <= def.y2 or
				pos.y <= def.y1 and pos.y >= def.y2 then
				
				if pos.z >= def.z1 and pos.z <= def.z2 or
					pos.z <= def.z1 and pos.z >= def.z2 then
					
					if name == def.owner then
						return true
					else
						r = false
					end
				end
			end
		end
	end
	
	return r
end

function HasOwner(pos)
	for _,def in pairs(owner_defs) do
		if pos.x >= def.x1 and pos.x <= def.x2 or
			pos.x <= def.x1 and pos.x >= def.x2 then
			
			if pos.y >= def.y1 and pos.y <= def.y2 or
				pos.y <= def.y1 and pos.y >= def.y2 then
				
				if pos.z >= def.z1 and pos.z <= def.z2 or
					pos.z <= def.z1 and pos.z >= def.z2 then
					
					return true
				end
			end
		end
	end
	
	return false
end

function getPlayerNodeOwner(pos)
	for _,def in pairs(owner_defs) do
		if pos.x >= def.x1 and pos.x <= def.x2 or
			pos.x <= def.x1 and pos.x >= def.x2 then
			
			if pos.y >= def.y1 and pos.y <= def.y2 or
				pos.y <= def.y1 and pos.y >= def.y2 then
				
				if pos.z >= def.z1 and pos.z <= def.z2 or
					pos.z <= def.z1 and pos.z >= def.z2 then
					return def.owner
				end
			end
		end
	end
	return ''
end

old_node_place = minetest.item_place
function minetest.item_place(itemstack, placer, pointed_thing)
	if itemstack:get_definition().type == "node" then
		local pos = pointed_thing.above
		if HasOwner(pos) then
			if not IsPlayerNodeOwner(pos, placer:get_player_name()) then
				minetest.chat_send_player(placer:get_player_name(), "Voce nao pode colocar blocos na propriedade de '"..getPlayerNodeOwner(pos).."'.")
				local player = minetest.env:get_player_by_name(getPlayerNodeOwner(pos))
				if player ~= nil and placer:get_player_name() ~= "" and minetest.setting_getbool("lunonodes_alertowner") then --Verifica se o proprietario esta online
					minetest.sound_play("sound_doorbell", {pos=player:getpos(), max_hear_distance = 10})
					minetest.chat_send_player(getPlayerNodeOwner(pos), "########### '"..placer:get_player_name().."' esta tentando colocar blocos na area de '"..getPlayerNodeOwner(pos).."'.")
				end
				return itemstack
			end
		end
		return old_node_place(itemstack, placer, pointed_thing)
	end
	
	return old_node_place(itemstack, placer, pointed_thing)
end

old_node_dig = minetest.node_dig
function minetest.node_dig(pos, node, digger)
	if minetest.get_node(pos).name ~= "bones:bones" and HasOwner(pos) then
		if not IsPlayerNodeOwner(pos, digger:get_player_name()) then
			minetest.chat_send_player(digger:get_player_name(), "Voce nao pode cavar blocos na propriedade de '"..getPlayerNodeOwner(pos).."'.")
			local player = minetest.env:get_player_by_name(getPlayerNodeOwner(pos))
			if player ~= nil and digger:get_player_name() ~= "" and minetest.setting_getbool("lunonodes_alertowner") then --Verifica se o proprietario esta online
				minetest.sound_play("sound_doorbell", {pos=player:getpos(), max_hear_distance = 10})
				minetest.chat_send_player(getPlayerNodeOwner(pos), "########### '"..digger:get_player_name().."' esta tentando cavar na area de '"..getPlayerNodeOwner(pos).."'.")
			end
			return
		end
	end
	old_node_dig(pos, node, digger)
end

function CheckCollisions(pos1, pos2)
	-- Find all 8 cube corners and make sure all 8 are not already in someone elses zone
	pos3 = {x=pos2.x,y=pos1.y,z=pos1.z}
	pos4 = {x=pos1.x,y=pos2.y,z=pos1.z}
	pos5 = {x=pos1.x,y=pos2.y,z=pos2.z}
	pos6 = {x=pos1.x,y=pos1.y,z=pos2.z}
	pos7 = {x=pos2.x,y=pos2.y,z=pos1.z}
	pos8 = {x=pos2.x,y=pos1.y,z=pos2.z}
	
	if HasOwner(pos1) == false and
		HasOwner(pos2) == false and
		HasOwner(pos3) == false and
		HasOwner(pos4) == false and
		HasOwner(pos5) == false and
		HasOwner(pos6) == false and
		HasOwner(pos7) == false and
		HasOwner(pos8) == false then
		return false
	end
	
	return true
end

function RemoveTableEntryRe(r_id)
	--Find child entries and remove them
	for n,def in pairs(owner_defs) do
		if def.parent == r_id then
			RemoveTableEntryRe(def.id)
		end
	end
	-- now remove main entry
	for n,def in pairs(owner_defs) do
		if def.id == r_id then
			table.remove(owner_defs, n)
			break
		end
	end
end

function RemoveTableEntry(r_id)
	RemoveTableEntryRe(r_id)
	
	--Re-number ids to match place in table
	for n,ndef in pairs(owner_defs) do
		if ndef.id ~= n then
			for p,pdef in pairs(owner_defs) do
				if pdef.parent == ndef.id then
					pdef.parent = n
				end
			end
			ndef.id = n
		end
	end
	
	table_save( owner_defs, owners_db_filename )
end
